package app

import (
	"duanju-mq/pkg/config"
	"duanju-mq/pkg/log"
	"errors"
	"os"
	"runtime/pprof"
	"runtime/trace"
	"strconv"
	"strings"
	"time"
)

// mem /dump/to/path
// cpu /dump/to/path
// cpu:60 /dump/to/path
// pprof:goroutine /dump/to/path
// trace /dump/to/path
// trace:60 /dump/to/path

var (
	fDump = config.String("lib.pprof.dump", "", "")

	handler = map[string]func(*os.File, string) error{
		"mem":   dumpMem,
		"cpu":   dumpCpu,
		"pprof": dumpPprof,
		"trace": dumpTrace,
	}
)

func init() {
	config.OnReload(dump)
}

func dump() {
	if *fDump == "" {
		return
	}
	ss := strings.SplitN(*fDump, " ", 2)
	if len(ss) != 2 {
		log.Err("lib.pprof.dump: format error")
		return
	}
	sss := strings.SplitN(ss[0], ":", 2)
	name := sss[0]
	args := ""
	if len(sss) > 1 {
		args = sss[1]
	}
	h, ok := handler[name]
	if !ok {
		log.Err("lib.pprof.dump: unknown pprof name")
		return
	}
	f, err := os.OpenFile(ss[1], os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(0666))
	if err != nil {
		log.Err("lib.pprof.dump:", err)
		return
	}
	defer f.Close()
	if err := h(f, args); err != nil {
		log.Err("lib.pprof.dump:", err)
		return
	}
	log.Debug("dump", name, "to", ss[1])
}

func dumpPprof(f *os.File, args string) error {
	p := pprof.Lookup(args)
	if p == nil {
		return errors.New("unknown pprof name")
	}
	return p.WriteTo(f, 0)
}

func dumpMem(f *os.File, args string) error {
	return pprof.Lookup("heap").WriteTo(f, 0)
}

func dumpCpu(f *os.File, args string) error {
	if err := pprof.StartCPUProfile(f); err != nil {
		return err
	}
	defer pprof.StopCPUProfile()
	d := time.Second * 30
	if args != "" {
		if v, _ := strconv.Atoi(args); v > 0 {
			d = time.Second * time.Duration(v)
		}
	}
	time.Sleep(d)
	return nil
}

func dumpTrace(f *os.File, args string) error {
	if err := trace.Start(f); err != nil {
		return err
	}
	defer trace.Stop()
	d := time.Second * 30
	if args != "" {
		if v, _ := strconv.Atoi(args); v > 0 {
			d = time.Second * time.Duration(v)
		}
	}
	time.Sleep(d)
	return nil
}
